package com.example.sonarqube;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * SonarQube 2025.3 API客户端，用于获取项目质量数据
 */
public class SonarQubeClient {
    private final String baseUrl;
    private final String token;
    private final HttpClient httpClient;
    private final ObjectMapper objectMapper;

    public SonarQubeClient(String baseUrl, String token) {
        this.baseUrl = baseUrl;
        this.token = token;
        
        // 初始化HTTP客户端
        this.httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .followRedirects(HttpClient.Redirect.NORMAL)
            .connectTimeout(Duration.ofSeconds(20))
            .build();
            
        // 初始化JSON解析器
        this.objectMapper = new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     * 获取项目列表
     * @return 项目列表
     * @throws IOException
     * @throws InterruptedException
     */
    public List<Project> getProjects() throws IOException, InterruptedException {
        String url = baseUrl + "/api/components/search?qualifiers=TRK";
        String response = sendRequest(url);
        
        // 解析响应
        ProjectsResponse projectsResponse = objectMapper.readValue(response, ProjectsResponse.class);
        return projectsResponse.getComponents();
    }

    /**
     * 获取项目指标
     * @param projectKey 项目Key
     * @param metricKeys 指标Key列表
     * @return 项目指标
     * @throws IOException
     * @throws InterruptedException
     */
    public ProjectMetrics getProjectMetrics(String projectKey, List<String> metricKeys) 
            throws IOException, InterruptedException {
        String metrics = String.join(",", metricKeys);
        String url = baseUrl + "/api/measures/component?component=" + projectKey + "&metricKeys=" + metrics;
        String response = sendRequest(url);
        
        // 解析响应
        return objectMapper.readValue(response, ProjectMetrics.class);
    }

    /**
     * 获取项目问题列表
     * @param projectKey 项目Key
     * @param maxResults 最大结果数
     * @return 问题列表
     * @throws IOException
     * @throws InterruptedException
     */
    public List<Issue> getProjectIssues(String projectKey, int maxResults) 
            throws IOException, InterruptedException {
        String url = baseUrl + "/api/issues/search?componentKeys=" + projectKey + "&ps=" + maxResults;
        String response = sendRequest(url);
        
        // 解析响应
        IssuesResponse issuesResponse = objectMapper.readValue(response, IssuesResponse.class);
        return issuesResponse.getIssues();
    }

    /**
     * 获取项目问题统计
     * @param projectKey 项目Key
     * @return 问题统计
     * @throws IOException
     * @throws InterruptedException
     */
    public IssueStatistics getIssueStatistics(String projectKey) 
            throws IOException, InterruptedException {
        // 获取所有问题类型的统计
        List<Issue> issues = getProjectIssues(projectKey, 500);
        
        // 按类型统计
        Map<String, Integer> typeCount = new HashMap<>();
        // 按严重程度统计
        Map<String, Integer> severityCount = new HashMap<>();
        // 按开发者统计
        Map<String, Integer> developerCount = new HashMap<>();
        
        for (Issue issue : issues) {
            // 统计问题类型
            typeCount.put(issue.getType(), typeCount.getOrDefault(issue.getType(), 0) + 1);
            
            // 统计严重程度
            severityCount.put(issue.getSeverity(), severityCount.getOrDefault(issue.getSeverity(), 0) + 1);
            
            // 统计开发者
            if (issue.getAssignee() != null && !issue.getAssignee().isEmpty()) {
                developerCount.put(issue.getAssignee(), developerCount.getOrDefault(issue.getAssignee(), 0) + 1);
            }
        }
        
        return new IssueStatistics(typeCount, severityCount, developerCount);
    }

    /**
     * 获取开发者列表
     * @param projectKey 项目Key
     * @return 开发者列表
     * @throws IOException
     * @throws InterruptedException
     */
    public List<User> getProjectDevelopers(String projectKey) 
            throws IOException, InterruptedException {
        // 从问题中获取所有开发者
        List<Issue> issues = getProjectIssues(projectKey, 500);
        
        // 提取所有唯一的开发者
        List<String> developerLogins = issues.stream()
            .map(Issue::getAssignee)
            .filter(login -> login != null && !login.isEmpty())
            .distinct()
            .collect(Collectors.toList());
            
        // 获取开发者详细信息
        List<User> developers = new ArrayList<>();
        for (String login : developerLogins) {
            User user = getUser(login);
            if (user != null) {
                developers.add(user);
            }
        }
        
        return developers;
    }

    /**
     * 获取用户信息
     * @param login 用户登录名
     * @return 用户信息
     * @throws IOException
     * @throws InterruptedException
     */
    public User getUser(String login) throws IOException, InterruptedException {
        String url = baseUrl + "/api/users/search?q=" + login;
        String response = sendRequest(url);
        
        // 解析响应
        UsersResponse usersResponse = objectMapper.readValue(response, UsersResponse.class);
        
        // 查找匹配的用户
        return usersResponse.getUsers().stream()
            .filter(user -> user.getLogin().equals(login))
            .findFirst()
            .orElse(null);
    }

    /**
     * 发送HTTP请求
     * @param url 请求URL
     * @return 响应内容
     * @throws IOException
     * @throws InterruptedException
     */
    private String sendRequest(String url) throws IOException, InterruptedException {
        // 创建HTTP请求
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .header("Accept", "application/json")
            .header("Authorization", "Basic " + java.util.Base64.getEncoder().encodeToString((token + ":").getBytes()))
            .GET()
            .build();
            
        // 发送请求并获取响应
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        
        // 检查响应状态
        if (response.statusCode() != 200) {
            throw new IOException("HTTP request failed with status code: " + response.statusCode());
        }
        
        return response.body();
    }

    // 内部类：项目
    public static class Project {
        private String key;
        private String name;
        private String qualifier;
        
        // Getters and setters
        public String getKey() { return key; }
        public void setKey(String key) { this.key = key; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getQualifier() { return qualifier; }
        public void setQualifier(String qualifier) { this.qualifier = qualifier; }
        
        @Override
        public String toString() {
            return "Project{key='" + key + "', name='" + name + "', qualifier='" + qualifier + "'}";
        }
    }

    // 内部类：项目响应
    public static class ProjectsResponse {
        private List<Project> components;
        
        // Getters and setters
        public List<Project> getComponents() { return components; }
        public void setComponents(List<Project> components) { this.components = components; }
    }

    // 内部类：项目指标
    public static class ProjectMetrics {
        private Component component;
        
        // Getters and setters
        public Component getComponent() { return component; }
        public void setComponent(Component component) { this.component = component; }
    }

    // 内部类：组件
    public static class Component {
        private String key;
        private String name;
        private String qualifier;
        private List<Measure> measures;
        
        // Getters and setters
        public String getKey() { return key; }
        public void setKey(String key) { this.key = key; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getQualifier() { return qualifier; }
        public void setQualifier(String qualifier) { this.qualifier = qualifier; }
        public List<Measure> getMeasures() { return measures; }
        public void setMeasures(List<Measure> measures) { this.measures = measures; }
    }

    // 内部类：指标
    public static class Measure {
        private String metric;
        private String value;
        
        // Getters and setters
        public String getMetric() { return metric; }
        public void setMetric(String metric) { this.metric = metric; }
        public String getValue() { return value; }
        public void setValue(String value) { this.value = value; }
    }

    // 内部类：问题
    public static class Issue {
        private String key;
        private String rule;
        private String severity;
        private String component;
        private String project;
        private Integer line;
        private String message;
        private String status;
        private String resolution;
        private String type;
        private String assignee;
        private String creationDate;
        private String updateDate;
        
        // Getters and setters
        public String getKey() { return key; }
        public void setKey(String key) { this.key = key; }
        public String getRule() { return rule; }
        public void setRule(String rule) { this.rule = rule; }
        public String getSeverity() { return severity; }
        public void setSeverity(String severity) { this.severity = severity; }
        public String getComponent() { return component; }
        public void setComponent(String component) { this.component = component; }
        public String getProject() { return project; }
        public void setProject(String project) { this.project = project; }
        public Integer getLine() { return line; }
        public void setLine(Integer line) { this.line = line; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }
        public String getResolution() { return resolution; }
        public void setResolution(String resolution) { this.resolution = resolution; }
        public String getType() { return type; }
        public void setType(String type) { this.type = type; }
        public String getAssignee() { return assignee; }
        public void setAssignee(String assignee) { this.assignee = assignee; }
        public String getCreationDate() { return creationDate; }
        public void setCreationDate(String creationDate) { this.creationDate = creationDate; }
        public String getUpdateDate() { return updateDate; }
        public void setUpdateDate(String updateDate) { this.updateDate = updateDate; }
        
        @Override
        public String toString() {
            return "Issue{key='" + key + "', rule='" + rule + "', severity='" + severity + "', component='" + component + "', type='" + type + "'}";
        }
    }

    // 内部类：问题响应
    public static class IssuesResponse {
        private List<Issue> issues;
        
        // Getters and setters
        public List<Issue> getIssues() { return issues; }
        public void setIssues(List<Issue> issues) { this.issues = issues; }
    }

    // 内部类：问题统计
    public static class IssueStatistics {
        private Map<String, Integer> typeCount;
        private Map<String, Integer> severityCount;
        private Map<String, Integer> developerCount;
        
        public IssueStatistics(Map<String, Integer> typeCount, Map<String, Integer> severityCount, 
                Map<String, Integer> developerCount) {
            this.typeCount = typeCount;
            this.severityCount = severityCount;
            this.developerCount = developerCount;
        }
        
        // Getters
        public Map<String, Integer> getTypeCount() { return typeCount; }
        public Map<String, Integer> getSeverityCount() { return severityCount; }
        public Map<String, Integer> getDeveloperCount() { return developerCount; }
    }

    // 内部类：用户
    public static class User {
        private String login;
        private String name;
        private String email;
        private boolean active;
        private String avatar;
        private String createdAt;
        private String updatedAt;
        
        // Getters and setters
        public String getLogin() { return login; }
        public void setLogin(String login) { this.login = login; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        public boolean isActive() { return active; }
        public void setActive(boolean active) { this.active = active; }
        public String getAvatar() { return avatar; }
        public void setAvatar(String avatar) { this.avatar = avatar; }
        public String getCreatedAt() { return createdAt; }
        public void setCreatedAt(String createdAt) { this.createdAt = createdAt; }
        public String getUpdatedAt() { return updatedAt; }
        public void setUpdatedAt(String updatedAt) { this.updatedAt = updatedAt; }
        
        @Override
        public String toString() {
            return "User{login='" + login + "', name='" + name + "', email='" + email + "'}";
        }
    }

    // 内部类：用户响应
    public static class UsersResponse {
        private List<User> users;
        
        // Getters and setters
        public List<User> getUsers() { return users; }
        public void setUsers(List<User> users) { this.users = users; }
    }

    // 示例用法
    public static void main(String[] args) {
        try {
            // 创建客户端实例
            SonarQubeClient client = new SonarQubeClient("http://localhost:9000", "your_token_here");
            
            // 获取项目列表
            List<Project> projects = client.getProjects();
            System.out.println("项目列表:");
            for (Project project : projects) {
                System.out.println("  - " + project.getName() + " (" + project.getKey() + ")");
            }
            
            if (!projects.isEmpty()) {
                // 获取第一个项目的指标
                String projectKey = projects.get(0).getKey();
                List<String> metricKeys = List.of("ncloc", "coverage", "bugs", "vulnerabilities", "code_smells");
                ProjectMetrics metrics = client.getProjectMetrics(projectKey, metricKeys);
                
                System.out.println("\n项目指标 (" + projects.get(0).getName() + "):");
                for (Measure measure : metrics.getComponent().getMeasures()) {
                    System.out.println("  - " + measure.getMetric() + ": " + measure.getValue());
                }
                
                // 获取项目问题统计
                IssueStatistics statistics = client.getIssueStatistics(projectKey);
                
                System.out.println("\n问题类型统计:");
                statistics.getTypeCount().forEach((type, count) -> {
                    System.out.println("  - " + type + ": " + count);
                });
                
                System.out.println("\n严重程度统计:");
                statistics.getSeverityCount().forEach((severity, count) -> {
                    System.out.println("  - " + severity + ": " + count);
                });
                
                // 获取项目开发者
                List<User> developers = client.getProjectDevelopers(projectKey);
                
                System.out.println("\n项目开发者:");
                for (User developer : developers) {
                    System.out.println("  - " + developer.getName() + " (" + developer.getLogin() + ")");
                }
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}    